/**   
 * @fileName XmlInjector.java
 * @package com.sllx.frost.ioc.inject
 * @copyright (c) 2014, sincerebravefight@gmail.com All Rights Reserved. 
 * @description 注射器
 * @author sllx  
 * @date 2014-5-9 下午3:28:05
 * @modifiedBy sllx
 * @ModifiedDate 2014-5-9 下午3:28:05
   * Why & What is modified
 * @version V1.0
 */
package com.sllx.frost.ioc.inject;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.sllx.frost.ioc.config.xml.Bean;
import com.sllx.frost.ioc.config.xml.Property;
import com.sllx.frost.ioc.config.xml.Structure;


/**
 * @className XmlInjector
 * @description 注射器
 * @author sllx
 * @date 2014-5-9 下午3:28:05
 * @modifiedBy sllx
 * @ModifiedDate 2014-5-9 下午3:28:05
 * Why & What is modified
 */
public class XmlInjector {
	
	/**
	 * 容器
	 */
	private static Map<String, Object> beans;
	
	/**
	 * 配置
	 */
	private static Structure structure;
	
	
	/**
	 * 核心方法，调用后会初始化bean容器，并组装完成。
	 * @param structure
	 * @return Map<String, Object>
	 */
	public static Map<String, Object> inject(Structure structure){
		XmlInjector.structure = structure;
		initBeans();
		assemble();
		return beans;
	}
	
	
	/**
	 * 初始化容器并添加bean
	 */
	private static void initBeans(){
		beans = new HashMap<String, Object>();
		for(Bean bean : structure.getBeans()){
			createBean(bean);
		}
	}
	
	
	/**
	 * 添加一个bean
	 * @param bean
	 */
	private static void createBean(Bean bean){
		String id = bean.getId();
		Object obj = null;
		try {
			obj = Class.forName(bean.getClassName()).newInstance();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		beans.put(id, obj);
	}
	
	
	/**
	 * 将容器中的bean按配置进行组合
	 */
	private static void assemble(){
		for(Bean bean : structure.getBeans()){
			setChildrenToParent(bean);
		}
	}
	
	
	/**
	 * 将子对象Set进父对象
	 * @param bean
	 */
	private static void setChildrenToParent(Bean bean){
		Object parent = beans.get(bean.getId());
		for(Property property : bean.getProperties()){
			injectByProperty(parent, property);
		}
	}
	
	
	/**
	 * 根据配置将子对象set进一个父对象
	 * @param parent
	 * @param property
	 */
	private static void injectByProperty(Object parent, Property property){
		String ref = property.getRef();
		String name = property.getName();
		Object child = beans.get(ref);				//获取子对象
		Method method = getMethod(name, parent);		//获取父对象中的set方法
		invoke(parent, method, child);				//执行父对象中的set方法，将子对象传入
	}
	
	
	/**
	 * 获取父对象中的Set方法
	 * @param name
	 * @param parent
	 * @return Method
	 */
	private static Method getMethod(String name, Object parent){
		String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
		Method method = null;
		try {
			Method[] methods = parent.getClass().getMethods();
			for(Method mtd : methods){
				if(mtd.getName().equals(methodName)){
					method = mtd;
					break;
				}
			}
			if(method == null){
				String message = parent.getClass().getName()+"."+methodName+"(*) not found, make sure it exists and is public";
				throw new NoSuchMethodException(message);
			}
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		}
		return method;
	}
	
	
	/**
	 * 执行方法
	 * @param parent
	 * @param method
	 * @param child
	 */
	private static void invoke(Object parent, Method method, Object child){
		try {
			method.invoke(parent, child);
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
	}
}
